package cn.mw.cmdb.virtualization.strategy.handler.query;

import cn.mw.cmdb.template.utils.TemplateSortUtil;
import cn.mw.cmdb.virtualization.annotations.VirtualizationAlias;
import cn.mw.cmdb.virtualization.constant.MwVirtualizationConstant;
import cn.mw.cmdb.virtualization.dto.*;
import cn.mw.cmdb.virtualization.enums.VirtualizationDataTypeEnum;
import cn.mw.cmdb.virtualization.param.VirtualizationParam;
import cn.mw.cmdb.virtualization.strategy.handler.HostDtoHandler;
import cn.mw.cmdb.virtualization.strategy.handler.VMDtoHandler;
import cn.mw.cmdb.virtualization.strategy.handler.VirtualizationTypeHandler;
import cn.mw.cmdb.virtualization.utils.VirtualizationDataFilterUtil;
import cn.mw.components.mongodb.entity.SearchParam;
import cn.mw.main.api.common.ZabbixDubboService;
import cn.mw.microMonitorCommon.constants.ZabbixApiConstants;
import cn.mw.microMonitorCommon.entity.zabbix.MWZabbixAPIResult;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @description 虚拟化、数据中心、主机池、集群数据
 */
@Service
@Slf4j
public class VirtualizationDataTypeHandler implements VirtualizationTypeHandler {

    @DubboReference(check = false, timeout = 120000)
    private ZabbixDubboService zabbixDubboService;

    @Override
    public List<String> getType() {
        return Arrays.asList(VirtualizationDataTypeEnum.HOST_LIST.getDataType(), VirtualizationDataTypeEnum.VM_LIST.getDataType());
    }

    @Override
    public Object getTypeData(List<VirtualizationBaseDto> baseDtos, VirtualizationParam param, Integer serverId) {
        VirtualizationDto virtualizationDto = new VirtualizationDto();
        try {
            VirtualizationDataTypeEnum dataTypeEnum = VirtualizationDataTypeEnum.valueOf(param.getQueryType());
            //获取hostID集合
            List<String> hostIds = baseDtos.stream().filter(item -> StringUtils.isNotEmpty(item.getHostId())).map(s -> s.getHostId()).collect(Collectors.toList());
            //查询主机需要的数据
            List<String> itemNames = getItemNames(dataTypeEnum);
            //查询zabbix数据
            MWZabbixAPIResult result = zabbixDubboService.getZabbixApiResult(ZabbixApiConstants.ITEM_GET_BY_SEARCH, serverId, itemNames, hostIds);
            if(result == null || result.isFail()){
                dataIsNull(dataTypeEnum,baseDtos,virtualizationDto,param);
                return virtualizationDto;
            }
            List<ItemLatestConvertDto> latestConvertDtos = JSONArray.parseArray(String.valueOf(result.getData()), ItemLatestConvertDto.class);
            if(CollectionUtils.isEmpty(latestConvertDtos)){
                dataIsNull(dataTypeEnum,baseDtos,virtualizationDto,param);
                return virtualizationDto;
            }
            Map<String, List<ItemLatestConvertDto>> hostItemMap = latestConvertDtos.stream().collect(Collectors.groupingBy(item -> item.getHostid()));
            Map<String, VirtualizationBaseDto> baseDtoMap = baseDtos.stream().collect(Collectors.toMap(s -> s.getHostId(), s -> s));
            List realDatas = new ArrayList();
            for (String hostId : hostItemMap.keySet()) {
                List<ItemLatestConvertDto> dtos = hostItemMap.get(hostId);
                VirtualizationBaseDto virtualizationBaseDto = baseDtoMap.get(hostId);
                switch (dataTypeEnum){
                    case HOST_LIST:
                        VirtualizationHostDto hostDto = new VirtualizationHostDto();
                        BeanUtils.copyProperties(virtualizationBaseDto,hostDto);
                        setFieldInfo(VirtualizationHostDto.class,hostDto,dtos);
                        hostDto.setType(param.getVmType());
                        realDatas.add(hostDto);
                        break;
                    case VM_LIST:
                        VirtualizationVMDto vmDto = new VirtualizationVMDto();
                        BeanUtils.copyProperties(virtualizationBaseDto,vmDto);
                        setFieldInfo(VirtualizationVMDto.class,vmDto,dtos);
                        vmDto.setType(param.getVmType());
                        realDatas.add(vmDto);
                }
            }
            virtualizationDto = handlerData(realDatas, dataTypeEnum,param);
        }catch (Throwable e){
            log.error("VirtualizationBasicTypeHandler{} getTypeData() error",e);
        }
        return virtualizationDto;
    }


    private void dataIsNull(VirtualizationDataTypeEnum dataTypeEnum,List<VirtualizationBaseDto> baseDtos,VirtualizationDto virtualizationDto,VirtualizationParam param){
        List realDatas = new ArrayList();
        for (VirtualizationBaseDto baseDto : baseDtos) {
            switch (dataTypeEnum){
                case HOST_LIST:
                    VirtualizationHostDto hostDto = new VirtualizationHostDto();
                    BeanUtils.copyProperties(baseDto,hostDto);
                    realDatas.add(hostDto);
                    break;
                case VM_LIST:
                    VirtualizationVMDto vmDto = new VirtualizationVMDto();
                    BeanUtils.copyProperties(baseDto,vmDto);
                    realDatas.add(vmDto);
            }
        }
        Page page = pageHandler(realDatas, param.getPageNum(), param.getPageSize());
        virtualizationDto.setDetailData(page);
    }

    private VirtualizationDto handlerData(List realDatas,VirtualizationDataTypeEnum dataTypeEnum,VirtualizationParam param){
        VirtualizationDto virtualizationDto = new VirtualizationDto();
        switch (dataTypeEnum){
            case HOST_LIST:
                HostDtoHandler handler = new HostDtoHandler();
                virtualizationDto = handler.handler(realDatas);
                break;
            case VM_LIST:
                VMDtoHandler vmDtoHandler = new VMDtoHandler();
                virtualizationDto = vmDtoHandler.handler(realDatas);
        }
        //数据过滤
        realDatas = VirtualizationDataFilterUtil.dataFilter(realDatas, param.getQueryKey(), param.getQueryValue());
        //排序处理
        if(StringUtils.isNotEmpty(param.getSortName()) && StringUtils.isNotEmpty(param.getSortOrder())){
            SearchParam searchParam = new SearchParam();
            searchParam.setSortName(param.getSortName());
            searchParam.setSortOrder(param.getSortOrder());
            realDatas = TemplateSortUtil.templateSortList(realDatas, searchParam, null);
        }
        //分页处理
        Page page = pageHandler(realDatas, param.getPageNum(), param.getPageSize());
        virtualizationDto.setDetailData(page);
        return virtualizationDto;
    }

    private Page pageHandler(List realDatas, Integer pageNum, Integer pageSize){
        if(CollectionUtils.isNotEmpty(realDatas)){
            //根据分页信息分割数据
            int fromIndex = pageSize * (pageNum -1);
            int toIndex = pageSize * pageNum;
            if(toIndex > realDatas.size()){
                toIndex = realDatas.size();
            }
            List<Map<String,Object>> pageList = realDatas.subList(fromIndex, toIndex);
            Page page = new Page();
            page.setRecords(pageList);
            page.setTotal(realDatas.size());
            return page;
        }
        return new Page();
    }


    private List<String> getItemNames(VirtualizationDataTypeEnum dataTypeEnum){
        switch (dataTypeEnum){
            case HOST_LIST:
                return MwVirtualizationConstant.HOST_ITEMS;
            case VM_LIST:
                return MwVirtualizationConstant.VM_ITEMS;
        }
        return null;
    }

    private void setFieldInfo(Class cls,Object obj,List<ItemLatestConvertDto> convertDtos) throws IllegalAccessException {
        for (ItemLatestConvertDto convertDto : convertDtos) {
            String name = convertDto.getName();
            if(name.contains("[")){
                name = name.split("]")[1];
            }
            Field[] fields = cls.getDeclaredFields();
            for (Field field : fields) {
                if(!field.isAnnotationPresent(VirtualizationAlias.class)){continue;}
                VirtualizationAlias fieldAnnotation = field.getAnnotation(VirtualizationAlias.class);
                String itemName = fieldAnnotation.itemName();
                if(StringUtils.isEmpty(itemName)){continue;}
                String[] itemNames = itemName.split(",");
                if(!Arrays.asList(itemNames).contains(name)){continue;}
                field.setAccessible(true);
                Object value = field.get(obj);
                String lastvalue = convertDto.getLastvalue();
                Boolean numeric = isNumeric(lastvalue);
                if(!numeric){
                    field.set(obj,lastvalue);
                    continue;
                }
                if(StringUtils.isNotEmpty(convertDto.getUnits())){
                    if(value != null){
                        String strValue = value.toString().split("_")[0];
                        field.set(obj, new BigDecimal(lastvalue).add(new BigDecimal(strValue))+"_"+convertDto.getUnits());
                    }else{
                        field.set(obj,lastvalue+"_"+convertDto.getUnits());
                    }
                }else{
                    if(value != null){
                        String strValue = value.toString().split("_")[0];
                        field.set(obj, new BigDecimal(lastvalue).add(new BigDecimal(strValue)));
                    }else{
                        field.set(obj,lastvalue);
                    }
                }

            }
        }
    }

    public Boolean isNumeric(String value) {
        // 定义数字的正则表达式，允许负号和小数点
        String numericRegex = "^[-+]?[0-9]*\\.?[0-9]+$";
        // 创建 Pattern 对象
        Pattern pattern = Pattern.compile(numericRegex);
        // 创建 Matcher 对象
        Matcher matcher = pattern.matcher(value);
        // 判断是否匹配
        if(!matcher.matches()){
            return false;
        }
        return true;
    }
}
